﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using Cofe.Core.Implements;

namespace Cofe.Data.Utils.ThirdParty
{
    //http://blogs.msdn.com/b/meek/archive/2008/05/02/linq-to-entities-combining-predicates.aspx
    //http://stackoverflow.com/questions/457316/combining-two-expressions-expressionfunct-bool
    public static class LambaUtils
    {
        public static Expression<Func<T, bool>> Not<T>(this Expression<Func<T, bool>> expr)
        {
            return Expression.Lambda<Func<T, bool>>(
                Expression.Not(expr.Body), expr.Parameters[0]);
        }


        public static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)
        {
            // build parameter map (from parameters of second to parameters of first)
            var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f);
            // replace parameters in the second lambda expression with parameters from the first
            var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);
            // apply composition of lambda expression bodies to parameters from the first expression 
            return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
        }


        public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
        {
            return first.Compose(second, Expression.And);
        }

        //public static Expression<Func<T, bool>> GreaterThan<T,PT>(this Expression<Func<T, PT>> first, Expression<Func<T, PT>> second)
        //{
        //    Expression<Func<T, bool>>.Block(Expression<Func<T, PT>>.GreaterThan(first, second))
        //    return first.Compose(second, Expression.GreaterThan);
        //}

        //public static Expression<Func<T, bool>> SmallerThan<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
        //{
        //    return first.Compose(second, Expression.GreaterThan);
        //}

        public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
        {
            return first.Compose(second, Expression.Or);
        }


        public static Expression<Func<CofeSystemInfo, bool>> EqualExpr<T>(
            Expression<Func<CofeSystemInfo, T>> pathExpression, T value)
        {
            return Expression.Lambda<Func<CofeSystemInfo, bool>>(
                Expression.Equal(pathExpression.Body, Expression.Constant(value)), pathExpression.Parameters.First());
        }

        public static Expression<Func<CofeSystemInfo, bool>> GreaterOrEqualExpr<T>(
            Expression<Func<CofeSystemInfo, T>> pathExpression, T value)
        {
            return Expression.Lambda<Func<CofeSystemInfo, bool>>(
                Expression.GreaterThanOrEqual(pathExpression.Body, Expression.Constant(value)), pathExpression.Parameters.First());
        }

        public static Expression<Func<CofeSystemInfo, bool>> LesserExpr<T>(
            Expression<Func<CofeSystemInfo, T>> pathExpression, T value)
        {
            return Expression.Lambda<Func<CofeSystemInfo, bool>>(
                Expression.LessThan(pathExpression.Body, Expression.Constant(value)), pathExpression.Parameters.First());
        }

        public static Expression<Func<CofeSystemInfo, bool>> StartWith<T>(
            Expression<Func<CofeSystemInfo, T>> pathExpression, T value)
        {
            
            return Expression.Lambda<Func<CofeSystemInfo, bool>>(
                Expression.GreaterThanOrEqual(pathExpression.Body, Expression.Constant(value)), pathExpression.Parameters.First());
        }
    }
}
